package me.boot.common.context;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import com.alibaba.ttl.TransmittableThreadLocal;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import me.base.utils.StrPool;
import me.boot.common.data.model.AppMode;
import me.boot.common.data.model.TenantInfo;
import me.boot.common.data.model.UserInfo;

import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


/**
 * 获取当前线程变量中的 用户id、用户昵称、租户编码、账号等信息
 */
@Slf4j
@UtilityClass
public class ContextUtil {

    /**
     * 支持多线程传递参数
     */
    private final ThreadLocal<Map<String, Object>> threadLocal = new TransmittableThreadLocal<>();

    public AppMode getAppMode() {
        return get(ContextConst.CONTEXT_APP_MODE, AppMode.class);
    }

    public void setAppMode(AppMode appMode) {
        set(ContextConst.CONTEXT_APP_MODE, appMode);
    }

    public Long getUserId() {
        UserInfo user = getUser();
        return user == null ? null : user.getUserId();
    }

    public UserInfo getUser() {
        return get(ContextConst.CONTEXT_USER, UserInfo.class);
    }

    public void setUser(UserInfo userInfo) {
        set(ContextConst.CONTEXT_USER, userInfo);
    }

    public String getTenantId() {
        TenantInfo tenant = getTenant();
        return tenant == null ? StrPool.EMPTY : String.valueOf(tenant.getId());
    }

    public TenantInfo getTenant() {
        return get(ContextConst.CONTEXT_TENANT, TenantInfo.class);
    }

    public void setTenant(TenantInfo tenantInfo) {
        set(ContextConst.CONTEXT_TENANT, tenantInfo);
    }


    public <T extends Serializable> void set(String key, T value) {
        Assert.notNull(key);
        Map<String, Object> map = getLocalMap();
        if (value != null) {
            map.put(key, value);
        } else {
            map.remove(key);
        }
    }

    public <T> T get(String key, Class<T> type) {
        Map<String, Object> map = getLocalMap();
        if (!map.containsKey(key)) {
            return null;
        }
        return Convert.convert(type, map.get(key));
    }

    public void clear() {
        threadLocal.remove();
    }

    private Map<String, Object> getLocalMap() {
        Map<String, Object> map = threadLocal.get();
        if (map == null) {
            map = new ConcurrentHashMap<>(10);
            threadLocal.set(map);
        }
        return map;
    }

}
